package cn.juque.datapipeline.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.juque.common.base.PageInfo;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.exception.AppException;
import cn.juque.datapipeline.api.enums.GroupExecuteStatusEnum;
import cn.juque.datapipeline.bo.group.TaskGroupInfoAddBO;
import cn.juque.datapipeline.bo.group.TaskGroupInfoUpdateBO;
import cn.juque.datapipeline.domain.TaskGroupRelationDO;
import cn.juque.datapipeline.entity.TaskGroupInfo;
import cn.juque.datapipeline.entity.TaskGroupRelation;
import cn.juque.datapipeline.entity.TaskInfo;
import cn.juque.datapipeline.helper.QuartzHelper;
import cn.juque.datapipeline.mapper.TaskGroupInfoMapper;
import cn.juque.datapipeline.mapper.TaskGroupRelationMapper;
import cn.juque.datapipeline.mapper.TaskInfoMapper;
import cn.juque.datapipeline.service.ITaskGroupInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author JUQUE
 * @version 1.0.0
 * <ul>
 *  <li>simple-generator</li>
 *  <li>任务组信息</li>
 * </ul>
 * {@code @date} 2023-04-02 14:23:40
 **/
@Service("taskGroupInfoService")
public class TaskGroupInfoServiceImpl implements ITaskGroupInfoService {

    @Resource
    private TaskGroupInfoMapper taskGroupInfoMapper;

    @Resource
    private TaskGroupRelationMapper taskGroupRelationMapper;

    @Resource
    private TaskInfoMapper taskInfoMapper;

    @Resource
    private QuartzHelper quartzHelper;

    /**
     * 分页查询
     *
     * @param pageInfo      pageInfo
     * @param taskGroupInfo taskGroupInfo
     * @return DataGrid
     */
    @Override
    public List<TaskGroupInfo> listGroupInfoWithPage(PageInfo pageInfo, TaskGroupInfo taskGroupInfo) {
        Page<TaskGroupInfo> page = new Page<>(pageInfo.getPage(), pageInfo.getLimit());
        List<TaskGroupInfo> list = this.taskGroupInfoMapper.queryGroupInfoList(page, taskGroupInfo);
        pageInfo.setTotal(page.getTotal());
        return list;
    }

    /**
     * 加载关联任务
     *
     * @param groupId 组ID
     * @return list
     */
    @Override
    public List<TaskGroupRelationDO> listTaskRelation(String groupId) {
        if (CharSequenceUtil.isEmpty(groupId)) {
            return CollUtil.newArrayList();
        }
        TaskGroupRelation relationQuery = new TaskGroupRelation();
        relationQuery.setTaskGroupId(groupId);
        List<TaskGroupRelation> relations = this.taskGroupRelationMapper.queryGroupRelationList(relationQuery);
        Set<String> taskIdSet = relations.stream().map(TaskGroupRelation::getTaskId).collect(Collectors.toSet());
        List<TaskInfo> taskList = this.taskInfoMapper.selectBatchIds(taskIdSet);
        Map<String, TaskInfo> taskMap = taskList.stream().collect(Collectors.toMap(TaskInfo::getId, t -> t, (k1, k2) -> k2));
        List<TaskGroupRelationDO> doList = BeanUtil.copyToList(relations, TaskGroupRelationDO.class);
        doList.forEach(f -> {
            TaskInfo taskInfo = taskMap.get(f.getTaskId());
            f.setTaskName(taskInfo.getTaskName());
            f.setTaskType(taskInfo.getTaskType());
        });
        return doList;
    }

    /**
     * 查询
     *
     * @param taskGroupInfo taskGroupInfo
     * @return List
     */
    @Override
    public List<TaskGroupInfo> listGroupInfoWithoutPage(TaskGroupInfo taskGroupInfo) {
        return this.taskGroupInfoMapper.queryGroupInfoList(taskGroupInfo);
    }

    /**
     * 详情
     *
     * @param id 主键
     * @return TaskGroupInfo
     */
    @Override
    public TaskGroupInfo detail(String id) {
        return this.taskGroupInfoMapper.selectById(id);
    }

    /**
     * 保存
     *
     * @param addBO TaskGroupInfoAddBO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveGroupInfo(TaskGroupInfoAddBO addBO) {
        TaskGroupInfo groupInfo = new TaskGroupInfo();
        BeanUtil.copyProperties(addBO, groupInfo);
        groupInfo.setExecuteStatus(GroupExecuteStatusEnum.WAIT.getCode());
        boolean flag = SqlHelper.retBool(this.taskGroupInfoMapper.insert(groupInfo));
        if (!flag) {
            throw new AppException(MessageEnum.SAVE_FAIL);
        }
        this.saveRelation(groupInfo.getId(), addBO.getTaskIdList());
        this.quartzHelper.addJob(groupInfo);
    }

    /**
     * 更新
     *
     * @param updateBO TaskGroupInfoUpdateBO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGroupInfo(TaskGroupInfoUpdateBO updateBO) {
        TaskGroupInfo source = this.taskGroupInfoMapper.selectById(updateBO.getId());
        TaskGroupInfo groupInfo = new TaskGroupInfo();
        BeanUtil.copyProperties(updateBO, groupInfo);
        boolean flag = SqlHelper.retBool(this.taskGroupInfoMapper.updateById(groupInfo));
        if (!flag) {
            throw new AppException(MessageEnum.UPDATE_FAIL);
        }
        this.saveRelation(groupInfo.getId(), updateBO.getTaskIdList());
        // 变更时长或corn，则重新创建任务
        boolean changeJob = null != updateBO.getDelaySeconds() && !updateBO.getDelaySeconds().equals(source.getDelaySeconds());
        changeJob = changeJob || (null != updateBO.getCron() && !updateBO.getCron().equals(source.getCron()));
        if (changeJob) {
            this.quartzHelper.deleteJob(groupInfo.getId());
            this.quartzHelper.addJob(groupInfo);
        }
    }

    /**
     * 禁用
     *
     * @param groupId 组ID
     */
    @Override
    public void triggerEnable(String groupId) {
        TaskGroupInfo taskGroupInfo = this.taskGroupInfoMapper.selectById(groupId);
        if (GroupExecuteStatusEnum.DISABLED.getCode().equals(taskGroupInfo.getExecuteStatus())) {
            taskGroupInfo.setExecuteStatus(GroupExecuteStatusEnum.WAIT.getCode());
            this.quartzHelper.resumeJob(groupId);
        } else {
            taskGroupInfo.setExecuteStatus(GroupExecuteStatusEnum.DISABLED.getCode());
            this.quartzHelper.pauseJob(groupId);
        }
        this.taskGroupInfoMapper.updateById(taskGroupInfo);
    }

    /**
     * 启动一次任务组
     *
     * @param groupId 组ID
     */
    @Override
    public void startOnce(String groupId) {
        this.quartzHelper.runOnce(groupId);
    }

    /**
     * 删除
     *
     * @param ids 主键列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteGroupInfo(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        int count = this.taskGroupInfoMapper.deleteBatchIds(ids);
        if (count != ids.size()) {
            throw new AppException(MessageEnum.DELETE_FAIL);
        }
        ids.forEach(id -> this.quartzHelper.deleteJob(id));
    }

    private void saveRelation(String groupId, List<String> taskIdList) {
        TaskGroupRelation queryRelation = new TaskGroupRelation();
        queryRelation.setTaskGroupId(groupId);
        this.taskGroupRelationMapper.delete(new QueryWrapper<>(queryRelation));
        if (CollUtil.isEmpty(taskIdList)) {
            return;
        }
        String taskId;
        for (int i = 0; i < taskIdList.size(); i++) {
            taskId = taskIdList.get(i);
            TaskGroupRelation relation = new TaskGroupRelation();
            relation.setTaskId(taskId);
            relation.setTaskGroupId(groupId);
            relation.setSortNo(i + 1);
            this.taskGroupRelationMapper.insert(relation);
        }
    }
}
